package com.neo.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.InMemoryRouteDefinitionRepository;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;

@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {
    private static final Logger log = LoggerFactory.getLogger(DynamicRouteServiceImpl.class);
    //    @Autowired
//    private RouteDefinitionWriter routeDefinitionWriter;

    @Autowired
    InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository;

    @Autowired
    RouteLocator routeLocator;

    private ApplicationEventPublisher publisher;


    public List<RouteDefinition> getRoutes() {
        routeLocator.getRoutes().subscribe(route -> {
            System.out.println(route.getId());
        });
        List<RouteDefinition> routeDefinitions = new ArrayList<>();
        inMemoryRouteDefinitionRepository.getRouteDefinitions().subscribe(routeDefinition -> {
            routeDefinitions.add(routeDefinition);
        });
        return routeDefinitions;
    }


    public boolean save(List<RouteDefinition> routeDefinitions) {
        try {
            if (null != routeDefinitions) {
                routeDefinitions.stream().forEach(routeDefinition -> {
                    inMemoryRouteDefinitionRepository.save(Mono.just(routeDefinition)).subscribe();
                });
                this.publisher.publishEvent(new RefreshRoutesEvent(this));
            }
            return true;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return false;
        }
    }

    public boolean save(RouteDefinition routeDefinition) {
        try {
            if (null != routeDefinition) {
                inMemoryRouteDefinitionRepository.save(Mono.just(routeDefinition)).subscribe();
                this.publisher.publishEvent(new RefreshRoutesEvent(this));
            }
            return true;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return false;
        }
    }

    public boolean cover(List<RouteDefinition> routeDefinitions) {
        if (!deleteAll()) {
            return false;
        }
        return save(routeDefinitions);
    }

    public boolean delete(String routeId) {
        try {
            inMemoryRouteDefinitionRepository.delete(Mono.just(routeId)).subscribe();
            this.publisher.publishEvent(new RefreshRoutesEvent(this));
            return true;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return false;
        }
    }

    public boolean deleteAll() {
        try {
            inMemoryRouteDefinitionRepository.getRouteDefinitions().subscribe(routeDefinition -> {
                inMemoryRouteDefinitionRepository.delete(Mono.just(routeDefinition.getId())).subscribe();
            });
//            Map<String, RouteDefinition> routes = (Map<String, RouteDefinition>) ReflectUtils.getPrivateParam(inMemoryRouteDefinitionRepository , "routes");
//            routes.clear();
            return true;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return false;
        }
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }
}
